package net.sudot.chess.business.controller.web;

import net.sudot.chess.business.controller.AbstractBaseController;
import net.sudot.chess.business.model.User;
import net.sudot.chess.business.service.UserService;
import net.sudot.chess.business.wechat.api.WechatApiService;
import net.sudot.chess.config.SystemProperties;
import net.sudot.commons.security.Jwt;
import net.sudot.commons.security.JwtAuthenticationFilter;
import net.sudot.commons.security.LoginUser;
import net.sudot.commons.utils.ResponseMessage;
import net.sudot.commons.utils.WebUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.SavedRequest;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 索引控制器
 *
 * @author tangjialin on 2018-03-21.
 */
@Controller
@RequestMapping
public class IndexController extends AbstractBaseController {

    @Resource
    private SystemProperties systemProperties;
    @Resource
    private ServerProperties serverProperties;
    @Resource
    private WechatApiService wechatApiService;
    @Resource
    private UserService userService;

    /** 微信服务器安全域名认证 */
    @GetMapping(value = "/MP_verify_{code}.txt", produces = "text/plain;charset=utf-8")
    @ResponseBody
    public String verify(@PathVariable("code") String code) {
        return code;
    }

    /**
     * 游戏大厅
     *
     * @return 返回游戏大厅视图
     */
    @GetMapping
    public String index() {
        return "game/index";
    }

    /**
     * 系统时间
     *
     * @return 返回系统时间
     */
    @GetMapping("/sysdate")
    @ResponseBody
    public Instant sysdate() {
        return Instant.now();
    }

    /**
     * 登录
     *
     * @param user 登录用户信息
     * @return 若已登录, 重定向游戏首页, 否则返回登录页面
     */
    @GetMapping("/login")
    public String login(@LoginUser User user, HttpServletRequest request) {
        String returnView = "login";
        if (user == null) {
            if (WebUtils.getUserAgent(request).toLowerCase().contains("micromessenger")) {
                SavedRequest savedRequest = org.apache.shiro.web.util.WebUtils.getAndClearSavedRequest(request);
                String redirectURI = systemProperties.getWebsite() + "/wechat/route?redirect=";
                redirectURI += savedRequest == null || !savedRequest.getMethod().equalsIgnoreCase(AccessControlFilter.GET_METHOD) ? "/" : savedRequest.getRequestUrl();
                // connect_redirect=1,这个参数微信公众号API中没有提到,此参数解决部分手机网页授权两次重定向跳转问题
                String oauth2Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect";
                redirectURI = String.format(oauth2Url, wechatApiService.getWxMpConfigStorage().getAppId(), redirectURI, "snsapi_userinfo", "login");
                returnView = "redirect:" + redirectURI;
            }
        } else {
            String redirect = Optional.ofNullable(org.apache.shiro.web.util.WebUtils.getAndClearSavedRequest(request))
                    .filter(savedRequest -> AccessControlFilter.GET_METHOD.equalsIgnoreCase(savedRequest.getMethod()))
                    .map(SavedRequest::getRequestUrl)
                    .orElse("/");
            returnView = "redirect:" + redirect;
        }
        return returnView;
    }

    /**
     * 登录操作
     * <pre>
     *     用户未登录的情况下访问此接口,会被shiro拦截进入方法:{@link JwtAuthenticationFilter#executeLogin(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}
     *     1.登录成功后{@link AuthenticatingFilter#onLoginSuccess(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.subject.Subject, javax.servlet.ServletRequest, javax.servlet.ServletResponse)}返回true会进入此方法
     *     2.用户已经登录的情况下调用此接口,则会进入此方法
     * </pre>
     *
     * @param user     登录用户信息
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @return 返回用户token等信息
     */
    @PostMapping("/login")
    @ResponseBody
    public Object loginSuccess(@LoginUser User user, HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> data = new HashMap<>();
        SavedRequest savedRequest = org.apache.shiro.web.util.WebUtils.getAndClearSavedRequest(request);
        if (savedRequest != null && savedRequest.getMethod().equalsIgnoreCase(AccessControlFilter.GET_METHOD)) {
            data.put(HttpHeaders.LOCATION, savedRequest.getRequestUrl());
        }
        String authToken = request.getHeader(JwtAuthenticationFilter.USER_TOKEN_HEADER_NAME);
        if (authToken == null || authToken.isEmpty()) {
            if (user == null) {
                user = (User) SecurityUtils.getSubject().getPrincipal();
            }
            authToken = Jwt.create(new Jwt.Payload(user.getId().toString(), serverProperties.getServlet().getSession().getTimeout()), systemProperties.getJwtSecret());
        }
        data.put("token", authToken);
        return data;
    }

    /**
     * 注册
     *
     * @return 返回注册视图
     */
    @GetMapping("/register")
    public String register() {
        return "register";
    }

    /**
     * 帮助中心
     *
     * @return 返回帮助中心视图
     */
    @GetMapping("/help")
    public String help() {
        return "help/index";
    }

    /**
     * 退出登录
     *
     * @return 返回主页
     */
    @GetMapping("/logout")
    public String logout() {
        userService.logout();
        return "redirect:/";
    }

    /**
     * 退出登录
     *
     * @return 退出信息
     */
    @PostMapping("/logout")
    @ResponseBody
    public ResponseMessage logout(@LoginUser User user) {
        userService.logout();
        return new ResponseMessage(true);
    }
}
